package api

import (
	"bridge_viewing/component/alisms"
	"bridge_viewing/config"
	"bridge_viewing/db"
	"bridge_viewing/dto"
	"bridge_viewing/enum"
	"bridge_viewing/global"
	"bridge_viewing/model"
	"bridge_viewing/service"
	"bridge_viewing/utils"
	"time"
)

type FetchPhoneVerifyCodeReq struct {
	dto.BaseReqParam
	UserPhone string `json:"user_phone"`
}

type LoginByPhoneAndCodeReq struct {
	dto.BaseReqParam
	UserPhone string `json:"user_phone"`
	Code      string `json:"code"`
}

type LoginInfo struct {
	Token string `json:"token"`
}

// FetchPhoneVerifyCodeApi @Description: 登录获取手机验证码
func FetchPhoneVerifyCodeApi(req *FetchPhoneVerifyCodeReq) (*dto.BaseRespParam, *enum.ErrorObj) {
	validateCode := utils.GenerateNumberCode(6)
	loginPhone := model.LoginPhoneCode{
		UserPhone: req.UserPhone,
		LoginCode: validateCode,
	}
	result := db.DBGClient.FirstOrCreate(&loginPhone, model.LoginPhoneCode{UserPhone: req.UserPhone})
	if result.RowsAffected == 0 {
		db.DBGClient.Model(&loginPhone).Update("login_code", validateCode)
	}
	global.GetLogger().InfoByTrace(&req.BaseParam, "user login send phone:%s, verify code:%s", req.UserPhone, validateCode)
	go func() {
		alisms.SmsClient.SendSMS(req.UserPhone, config.ServerGlobalConfig.AliyunSmsConfig.SmsSignName, config.ServerGlobalConfig.AliyunSmsConfig.TemplateCode,
			map[string]string{config.ServerGlobalConfig.AliyunSmsConfig.TemplateParamKey: validateCode})
	}()
	return &dto.BaseRespParam{}, nil
}

// LoginByPhoneAndCodeApi @Description: 手机号登录
func LoginByPhoneAndCodeApi(req *LoginByPhoneAndCodeReq) (*dto.CommonRespParam, *enum.ErrorObj) {
	errorObj := checkPhoneCode(req.UserPhone, req.Code)
	if errorObj != nil {
		return nil, errorObj
	}
	userId, err := registerUserInfoByPhone(&req.BaseParam, req.UserPhone)
	if err != nil {
		return nil, enum.NewErrorObj(err)
	}
	token, _ := utils.GenerateToken(userId)
	return &dto.CommonRespParam{
		Data: LoginInfo{
			Token: token,
		},
	}, nil
}

// FetchTokenApi @Description: 获取token
func FetchTokenApi(req *dto.BaseReqParam) (*dto.CommonRespParam, *enum.ErrorObj) {
	entityUserId, err := service.AddUserInfo(&req.BaseParam, "")
	if err != nil {
		return nil, enum.SystemErr
	}
	token, _ := utils.GenerateToken(entityUserId)
	return &dto.CommonRespParam{
		Data: LoginInfo{
			Token: token,
		},
	}, nil
}

func checkPhoneCode(userPhone string, code string) *enum.ErrorObj {
	var ret model.LoginPhoneCode
	if err := db.DBGClient.Where(model.LoginPhoneCode{UserPhone: userPhone}).First(&ret).Error; err != nil {
		return enum.ParamErr
	}
	if ret.LoginCode == code && time.Now().Sub(ret.UpdatedAt).Minutes() <= 5 {
		return nil
	}
	return enum.LoginErr
}

func registerUserInfoByPhone(baseParam *dto.BaseParam, userPhone string) (int, error) {
	userId := 0
	entityUser := service.GetUserByPhone(baseParam, userPhone)
	if entityUser == nil {
		entityUserId, err := service.AddUserInfo(baseParam, userPhone)
		if err != nil {
			return 0, err
		}
		userId = entityUserId
	} else {
		userId = entityUser.UserId
	}
	return userId, nil
}
